﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Controls;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Helpers;
using SvgPathProperties;

namespace AIStudio.Wpf.DiagramDesigner
{
    /// <summary>
    /// DefaultLink
    /// </summary>
    public class ConnectionViewModel : SelectableDesignerItemViewModelBase
    {
        public ConnectionViewModel()
        {

        }

        public ConnectionViewModel(ConnectorInfoBase sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode drawMode = DrawMode.ConnectingLineSmooth, RouterMode routerMode = AIStudio.Wpf.DiagramDesigner.RouterMode.RouterNormal) : this(null, sourceConnectorInfo, sinkConnectorInfo, drawMode, routerMode)
        {

        }

        public ConnectionViewModel(IDiagramViewModel root, ConnectorInfoBase sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode drawMode = DrawMode.ConnectingLineSmooth, RouterMode routerMode = AIStudio.Wpf.DiagramDesigner.RouterMode.RouterNormal) : base(root)
        {          
            _pathMode = drawMode.ToString();
            _routerMode = routerMode.ToString();
            Init(root, sourceConnectorInfo, sinkConnectorInfo);
        }

        public ConnectionViewModel(IDiagramViewModel root, ConnectorInfoBase sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, ConnectionItem designer) : base(root, designer)
        {
            _pathMode = designer.PathMode;
            _routerMode = designer.RouterMode;
            Init(root, sourceConnectorInfo, sinkConnectorInfo);
        }

        public override SelectableItemBase GetSerializableObject()
        {
            if (IsFullConnection)
            {
                ConnectionItem connection = new ConnectionItem(this);

                return connection;
            }
            else//Todo,半连接线也可序列化
            {
                return null;
            }
        }

        protected virtual void Init(IDiagramViewModel root, ConnectorInfoBase sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
        {
            IsLoaded = false;
            this.Root = root ?? sourceConnectorInfo.Root;
            if (sinkConnectorInfo is FullyCreatedConnectorInfo sink && sink.DataItem.ShowArrow == false)
            {
                this.ShapeViewModel.SinkMarker = new SharpPath("", 10, 10, PathStyle.None, SizeStyle.Middle);
            }         
            var routetype = TypeHelper.GetType(RouterMode);
            Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal();
            var pathGeneratortype = TypeHelper.GetType(PathMode);
            PathGenerator = pathGeneratortype != null ? (System.Activator.CreateInstance(pathGeneratortype) as IPathGenerator) : new ConnectingLineSmooth();
            IsLoaded= true;

            this.SourceConnectorInfo = sourceConnectorInfo;
            this.SinkConnectorInfo = sinkConnectorInfo;
            

            DeleteConnectionCommand = new SimpleCommand(Command_Enable, DeleteConnection);
            AddVertexCommand = new SimpleCommand(Command_Enable, AddVertex);
            AddLabelCommand = new SimpleCommand(Command_Enable, para => AddLabel());
        }

        protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
        {
            base.LoadDesignerItemViewModel(designerbase);

            if (designerbase is ConnectionItem designer)
            {
                Vertices = new ObservableCollection<ConnectorVertexModel>(designer.Vertices.Select(p => new ConnectorVertexModel(this.Root, this, designer)));
                Labels = new ObservableCollection<ConnectorLabelModel>(designer.Labels.Select(p => new ConnectorLabelModel(this.Root, this, designer)));
            }
        }

        #region 属性
        private string _text;
        [Browsable(true)]
        [CanDo]
        public override string Text
        {
            get
            {
                var text = _text;
                if (Labels?.Count > 0)
                {
                    text = Labels[0].Text;
                }

                if (FontViewModel.FontCase == FontCase.Upper)
                {
                    return text?.ToUpper();
                }
                else if (FontViewModel.FontCase == FontCase.Lower)
                {
                    return text?.ToLower();
                }
                else
                {
                    return text;
                }
            }
            set
            {
                if (SetProperty(ref _text, value))
                {
                    if (!string.IsNullOrEmpty(_text))
                    {
                        if (Labels?.Count > 0)
                        {
                            Labels[0].Text = _text;
                        }
                        else
                        {
                            AddLabel(_text);
                        }
                    }
                    else
                    {
                        ClearLabel();
                    }
                }
            }
        }

        private PointBase _sourceA;
        public PointBase SourceA
        {
            get
            {
                return _sourceA;
            }
            set
            {
                SetProperty(ref _sourceA, value);
            }
        }

        private PointBase _sourceB;
        public PointBase SourceB
        {
            get
            {
                return _sourceB;
            }
            set
            {
                SetProperty(ref _sourceB, value);
            }
        }

        private PointBase _startPoint;
        public PointBase StartPoint
        {
            get
            {
                return _startPoint;
            }
            private set
            {
                SetProperty(ref _startPoint, value);
            }
        }

        private PointBase _endPoint;
        public PointBase EndPoint
        {
            get
            {
                return _endPoint;
            }
            private set
            {
                SetProperty(ref _endPoint, value);
            }
        }

        private double _startAngle;
        public double StartAngle
        {
            get
            {
                return _startAngle;
            }
            private set
            {
                SetProperty(ref _startAngle, value);
            }
        }

        private double _endAngle;
        public double EndAngle
        {
            get
            {
                return _endAngle;
            }
            private set
            {
                SetProperty(ref _endAngle, value);
            }
        }

        private RectangleBase _startRectangle;
        public RectangleBase StartRectangle
        {
            get
            {
                return _startRectangle;
            }
            private set
            {
                SetProperty(ref _startRectangle, value);
            }
        }

        private RectangleBase _endRectangle;
        public RectangleBase EndRectangle
        {
            get
            {
                return _endRectangle;
            }
            private set
            {
                SetProperty(ref _endRectangle, value);
            }
        }

        private Thickness _dragThumbMargin;
        public Thickness DragThumbMargin
        {
            get
            {
                return _dragThumbMargin;
            }
            private set
            {
                SetProperty(ref _dragThumbMargin, value);
            }
        }

        private RectangleBase _area;
        public RectangleBase Area
        {
            get
            {
                return _area;
            }
            private set
            {
                SetProperty(ref _area, value);
            }
        }

        private string _pathMode;
        public string PathMode
        {
            get
            {
                return _pathMode;
            }
            set
            {
                SetProperty(ref _pathMode, value);
            }
        }

        private string _routerMode;
        public string RouterMode
        {
            get
            {
                return _routerMode;
            }
            set
            {
                SetProperty(ref _routerMode, value);
            }
        }

        public IRouter Router
        {
            get; set;
        }

        public IPathGenerator PathGenerator
        {
            get; set;
        }

        private PathGeneratorResult _pathGeneratorResult;
        public PathGeneratorResult PathGeneratorResult
        {
            get
            {
                return _pathGeneratorResult;
            }
            private set
            {
                SetProperty(ref _pathGeneratorResult, value);
            }
        }

        private bool _shouldInsertAnchor;
        public bool ShouldInsertAnchor
        {
            get
            {
                return _shouldInsertAnchor;
            }
            set
            {
                SetProperty(ref _shouldInsertAnchor, value);
            }
        }

        //待完善这两处
        private ObservableCollection<ConnectorVertexModel> _vertices = new ObservableCollection<ConnectorVertexModel>();
        public ObservableCollection<ConnectorVertexModel> Vertices
        {
            get
            {
                return _vertices;
            }
            private set
            {
                SetProperty(ref _vertices, value);
            }
        }

        private ObservableCollection<ConnectorLabelModel> _labels = new ObservableCollection<ConnectorLabelModel>();
        public ObservableCollection<ConnectorLabelModel> Labels
        {
            get
            {
                return _labels;
            }
            private set
            {
                SetProperty(ref _labels, value);
            }
        }

        public virtual Dictionary<string, string> PropertiesSetting
        {
            get
            {
                return new Dictionary<string, string>()
                {
                    { "Text","文本" },
                };
            }
        }

        private ConnectorInfoBase _sourceConnectorInfo;
        public ConnectorInfoBase SourceConnectorInfo
        {
            get
            {
                return _sourceConnectorInfo;
            }
            set
            {
                SetProperty(ref _sourceConnectorInfo, value);

            }
        }

        public FullyCreatedConnectorInfo SourceConnectorInfoFully
        {
            get
            {
                return SourceConnectorInfo as FullyCreatedConnectorInfo;
            }
        }

        public PartCreatedConnectorInfo SourceConnectorInfoPart
        {
            get
            {
                return SourceConnectorInfo as PartCreatedConnectorInfo;
            }
        }

        private ConnectorInfoBase _sinkConnectorInfo;
        public ConnectorInfoBase SinkConnectorInfo
        {
            get
            {
                return _sinkConnectorInfo;
            }
            set
            {
                SetProperty(ref _sinkConnectorInfo, value);

            }
        }

        public FullyCreatedConnectorInfo SinkConnectorInfoFully
        {
            get
            {
                return SinkConnectorInfo as FullyCreatedConnectorInfo;
            }
        }

        public PartCreatedConnectorInfo SinkConnectorInfoPart
        {
            get
            {
                return SinkConnectorInfo as PartCreatedConnectorInfo;
            }
        }

        public PointBase OnGoingPosition
        {
            get
            {
                return SinkConnectorInfoPart?.MiddlePosition ?? PointBase.Zero;
            }
        }

        public bool IsFullConnection
        {
            get
            {
                return SourceConnectorInfoFully != null && SinkConnectorInfoFully != null;
            }
        }

        public double SmoothMargin { get; set; } = 125;
        public double SmoothAutoSlope { get; set; } = 1;
        public double OrthogonalShapeMargin { get; set; } = 10;
        public double OrthogonalGlobalBoundsMargin { get; set; } = 50;

        public bool IsPortless => SourceConnectorInfoFully?.IsPortless == true || SinkConnectorInfoFully?.IsPortless == true;
        #endregion

        #region 方法
        public ICommand DeleteConnectionCommand
        {
            get; set;
        }

        public ICommand AddVertexCommand
        {
            get; set;
        }

        public ICommand AddLabelCommand
        {
            get; set;
        }
        #endregion

        protected override void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (IsLoaded == false || IsInternalChanged == true ) return;

            if (sender is ConnectionViewModel)
            {
                switch (e.PropertyName)
                {
                    case nameof(SourceA):
                    case nameof(SourceB):
                        UpdateArea();
                        break;
                    case nameof(Area):
                        UpdatePathGeneratorResult();
                        break;
                    case nameof(Vertices):
                        foreach (var vertice in Vertices)
                        {
                            vertice.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
                        }
                        break;
                    case nameof(Labels):
                        foreach (var label in Labels)
                        {
                            label.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
                        }
                        break;
                    case nameof(SourceConnectorInfo):
                        if (SourceConnectorInfo != null)
                        {
                            SourceA = SourceConnectorInfo.Position;
                            if (SourceConnectorInfoFully != null)
                            {
                                SourceConnectorInfoFully.DataItem.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
                            }
                        }
                        break;
                    case nameof(SinkConnectorInfo):
                        if (SinkConnectorInfo != null)
                        {
                            SourceB = SinkConnectorInfo.Position;
                            if (SinkConnectorInfoFully != null)
                            {
                                SinkConnectorInfoFully.DataItem.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
                            }
                        }
                        break;
                    case nameof(IsSelected):
                        if (IsSelected == false)
                        {
                            Labels.FirstOrDefault()?.AddToSelection(false, true);
                        }
                        break;
                    case nameof(RouterMode):
                        var routetype = TypeHelper.GetType(RouterMode);
                        Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal();
                        UpdatePathGeneratorResult();
                        break;
                    case nameof(PathMode):
                        var pathGeneratortype = TypeHelper.GetType(PathMode);
                        PathGenerator = pathGeneratortype != null ? (System.Activator.CreateInstance(pathGeneratortype) as IPathGenerator) : new ConnectingLineSmooth();
                        UpdatePathGeneratorResult();
                        break;
                }
            }
            else if (sender is ShapeViewModel)
            {
                if (e.PropertyName == nameof(ShapeViewModel.SourceMarker) ||
                   e.PropertyName == nameof(ShapeViewModel.SinkMarker))
                {
                    UpdatePathGeneratorResult();
                }
            }
            else if (sender is DesignerItemViewModelBase)
            {
                switch (e.PropertyName)
                {
                    case nameof(DesignerItemViewModelBase.ItemHeight):
                    case nameof(DesignerItemViewModelBase.ItemWidth):
                    case nameof(DesignerItemViewModelBase.Left):
                    case nameof(DesignerItemViewModelBase.Top):
                        if (IsFullConnection)
                        {
                            //减少触发一次画线
                            SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfoFully);
                            SourceB = PointHelper.GetPointForConnector(this.SinkConnectorInfoFully);
                        }
                        else
                        {
                            SourceA = SourceConnectorInfo.MiddlePosition;
                        }
                        break;
                }
            }
            else if (sender is ConnectorVertexModel connectorVertexModel)
            {
                switch (e.PropertyName)
                {
                    case nameof(ConnectorPointModel.X):
                    case nameof(ConnectorPointModel.Y):
                        if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.None)
                        {
                            UpdatePathGeneratorResult();
                        }
                        else if(connectorVertexModel.ConnectorVertexType == ConnectorVertexType.Start)
                        {
                            var nearPort = Root.FindNearPortToAttachTo(this, ConnectorVertexType.Start);
                            SetSourcePort(new PartCreatedConnectorInfo(connectorVertexModel.Position.X, connectorVertexModel.Position.Y));
                        }
                        else if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.End)
                        {
                            var nearPort = Root.FindNearPortToAttachTo(this, ConnectorVertexType.End);
                            SetSinkPort(new PartCreatedConnectorInfo(connectorVertexModel.Position.X, connectorVertexModel.Position.Y));
                        }
                        break;
                    case nameof(ConnectorPointModel.DragStart):
                        if (connectorVertexModel.DragStart == false)
                        {
                            if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.Start)
                            {
                                var nearPort = Root?.FindNearPortToAttachTo(this, ConnectorVertexType.Start);
                                if (nearPort != null)
                                {
                                    SetSourcePort(nearPort);
                                }
                            }
                            else if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.End)
                            {
                                var nearPort = Root?.FindNearPortToAttachTo(this, ConnectorVertexType.End);
                                if (nearPort != null)
                                {
                                    SetSinkPort(nearPort);
                                }
                            }
                            Root?.ClearAttachTo();
                        }
                        break;
                }
            }
            else if (sender is ConnectorLabelModel linkLabelModel)
            {
                switch (e.PropertyName)
                {
                    case nameof(ConnectorPointModel.X):
                        {
                            if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
                            {
                                linkLabelModel.UpdateOffsetX((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue);
                            }
                            break;
                        }
                    case nameof(ConnectorPointModel.Y):
                        {
                            if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
                            {
                                linkLabelModel.UpdateOffsetY((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue);
                            }
                            break;
                        }
                }
            }
            else if (sender is ColorViewModel)
            {

            }
        }

        public override bool Verify()
        {
            return IsFullConnection == false || SourceConnectorInfo?.CanAttachTo(SinkConnectorInfo) == true;
        }

        private void UpdateArea()
        {
            Area = new RectangleBase(SourceA, SourceB);
        }

        private void UpdatePathGeneratorResult()
        {
            if (SourceConnectorInfo == null || SinkConnectorInfo == null)
                return;

            var route = Router.Get(Root, this);

            (var source, var target) = FindConnectionPoints(route);
            if (source == null || target == null)
                return;

            PathGeneratorResult = PathGenerator.Get(Root, this, route, source.Value, target.Value);

            var startMiddle = new RectangleBase
                (
                (PathGeneratorResult.SourceMarkerPosition.X + (source.Value.X - Area.Left)) / 2,
                (PathGeneratorResult.SourceMarkerPosition.Y + (source.Value.Y - Area.Top)) / 2,
                0,
                0
                );
            var endMiddle = new RectangleBase
                (
                (PathGeneratorResult.TargetMarkerPosition.X + (target.Value.X - Area.Left)) / 2,
                (PathGeneratorResult.TargetMarkerPosition.Y + (target.Value.Y - Area.Top)) / 2,
                0,
                0
                );
            StartRectangle = startMiddle.InflateRectangle(GetSourceMarkerWidth() / 2, GetSourceMarkerHeight() / 2);
            EndRectangle = endMiddle.InflateRectangle(GetSinkMarkerWidth() / 2, GetSinkMarkerHeight() / 2);

            StartAngle = PathGeneratorResult.SourceMarkerAngle;
            EndAngle = PathGeneratorResult.TargetMarkerAngle;

            StartPoint = new PointBase(source.Value.X - Area.Left , source.Value.Y - Area.Top );
            EndPoint = new PointBase(target.Value.X - Area.Left , target.Value.Y - Area.Top);

            var startVertice = Vertices.FirstOrDefault(p => p.ConnectorVertexType == ConnectorVertexType.Start);
            if (startVertice == null)
            {               
                startVertice = AddEndsVertex(StartPoint, ConnectorVertexType.Start);
            }
            else
            {
                IsInternalChanged = true;
                startVertice.SetPosition(StartPoint);
                IsInternalChanged = true;
            }
            startVertice.ColorViewModel.FillColor.Color = SourceConnectorInfoFully != null? Colors.DarkRed : Colors.Blue;
            startVertice.ColorViewModel.LineColor.Color = SourceConnectorInfoFully != null ? Colors.DarkRed : Colors.Blue;

            var endVertice = Vertices.FirstOrDefault(p => p.ConnectorVertexType == ConnectorVertexType.End);
            if (endVertice == null)
            {
                endVertice = AddEndsVertex(EndPoint, ConnectorVertexType.End);
            }
            else
            {
                IsInternalChanged = true;
                endVertice.SetPosition(EndPoint);
                IsInternalChanged = false;
            }
            endVertice.ColorViewModel.FillColor.Color = SinkConnectorInfoFully != null ? Colors.DarkRed : Colors.Blue;
            endVertice.ColorViewModel.LineColor.Color = SinkConnectorInfoFully != null ? Colors.DarkRed : Colors.Blue;

            var paths = Labels.Count > 0 ? PathGeneratorResult.Paths.Select(p => new SvgPath(p)).ToArray() : Array.Empty<SvgPath>();
            foreach (var label in Labels)
            {
                label.UpdatePosition(paths);
            }

            double marginwidth = 0;
            double marginheight = 0;
            if (Area.Width > SourceConnectorInfo.ConnectorWidth + SinkConnectorInfo.ConnectorWidth)
            {
                marginwidth = (SourceConnectorInfo.ConnectorWidth + SinkConnectorInfo.ConnectorWidth) / 2;
            }
            if (Area.Height > SourceConnectorInfo.ConnectorHeight + SinkConnectorInfo.ConnectorHeight)
            {
                marginheight = (SourceConnectorInfo.ConnectorHeight + SinkConnectorInfo.ConnectorHeight) / 2;
            }
            DragThumbMargin = new Thickness(marginwidth, marginheight, marginwidth, marginheight);
        }

        private void DeleteConnection(object args)
        {
            if (this.Root is IDiagramViewModel)
            {
                var diagramVM = this.Root as IDiagramViewModel;
                diagramVM.DeleteCommand.Execute(this);
            }
        }

        private (PointBase? source, PointBase? target) FindConnectionPoints(PointBase[] route)
        {
            if (IsPortless) // Portless
            {
                if (SourceConnectorInfoFully?.DataItem == null || SinkConnectorInfoFully?.DataItem == null)
                    return (null, null);

                var sourceCenter = SourceConnectorInfoFully.IsPortless ? SourceConnectorInfoFully.DataItem.MiddlePosition : SourceConnectorInfoFully.MiddlePosition;
                var targetCenter = SinkConnectorInfoFully?.IsPortless == true ? SinkConnectorInfoFully?.DataItem?.MiddlePosition ?? OnGoingPosition : SinkConnectorInfoFully?.MiddlePosition ?? OnGoingPosition;
                var firstPt = route.Length > 0 ? route[0] : targetCenter;
                var secondPt = route.Length > 0 ? route[0] : sourceCenter;
                var sourceLine = new LineBase(firstPt, sourceCenter);
                var targetLine = new LineBase(secondPt, targetCenter);
                var sourceIntersections = SourceConnectorInfoFully.DataItem.GetShape().GetIntersectionsWithLine(sourceLine);
                var targetIntersections = SinkConnectorInfoFully?.DataItem?.GetShape()?.GetIntersectionsWithLine(targetLine) ?? new PointBase[] { OnGoingPosition };
                var sourceIntersection = GetClosestPointTo(sourceIntersections, firstPt);
                var targetIntersection = GetClosestPointTo(targetIntersections, secondPt);

                return (sourceIntersection ?? sourceCenter, targetIntersection ?? targetCenter);
            }
            else
            {
                var source = SourceConnectorInfo.MiddlePosition;//GetPortPositionBasedOnAlignment(SourceConnectorInfoFully, ColorViewModel.LeftArrowSizeStyle);
                var target = SinkConnectorInfo.MiddlePosition;// GetPortPositionBasedOnAlignment(SinkConnectorInfoFully, ColorViewModel.RightArrowSizeStyle);
                return (source, target);
            }


        }

        private PointBase? GetPortPositionBasedOnAlignment(ConnectorInfoBase port, SizeStyle marker)
        {
            if (port == null)
                return null;

            if (marker == 0)
                return port.MiddlePosition;

            var pt = port.Position;
            switch (port.Orientation)
            {
                case ConnectorOrientation.Top:
                    return new PointBase(pt.X + port.ConnectorWidth / 2, pt.Y);
                case ConnectorOrientation.TopRight:
                    return new PointBase(pt.X + port.ConnectorWidth, pt.Y);
                case ConnectorOrientation.Right:
                    return new PointBase(pt.X + port.ConnectorWidth, pt.Y + port.ConnectorHeight / 2);
                case ConnectorOrientation.BottomRight:
                    return new PointBase(pt.X + port.ConnectorWidth, pt.Y + port.ConnectorHeight);
                case ConnectorOrientation.Bottom:
                    return new PointBase(pt.X + port.ConnectorWidth / 2, pt.Y + port.ConnectorHeight);
                case ConnectorOrientation.BottomLeft:
                    return new PointBase(pt.X, pt.Y + port.ConnectorHeight);
                case ConnectorOrientation.Left:
                    return new PointBase(pt.X, pt.Y + port.ConnectorHeight / 2);
                default:
                    return pt;
            }
        }

        private PointBase? GetClosestPointTo(IEnumerable<PointBase> points, PointBase point)
        {
            var minDist = double.MaxValue;
            PointBase? minPoint = null;

            foreach (var pt in points)
            {
                var dist = pt.DistanceTo(point);
                if (dist < minDist)
                {
                    minDist = dist;
                    minPoint = pt;
                }
            }

            return minPoint;
        }

        public void SetSourcePort(ConnectorInfoBase port)
        {
            SourceConnectorInfo = port;
        }

        public void SetSinkPort(ConnectorInfoBase port)
        {
            SinkConnectorInfo = port;
        }

        public void SetPartPostion(PointBase? sourcePoint, PointBase? sinkPoint)
        {
            if (sourcePoint != null)
            {
                SourceConnectorInfoPart.Position = sourcePoint.Value;
                _sourceA = SourceConnectorInfoPart.Position;
            }
            if (sinkPoint != null)
            {
                SinkConnectorInfoPart.Position = sinkPoint.Value;
                _sourceB = SinkConnectorInfoPart.Position;
            }

            UpdateArea();
        }

        public void UpdateConnectionMode(FullyCreatedConnectorInfo source, FullyCreatedConnectorInfo sink, string pathmode, string routermode)
        {
            //先置空，避免更新
            SourceConnectorInfo = null;
            SinkConnectorInfo = null;
            PathMode = pathmode;
            RouterMode = routermode;
            SourceConnectorInfo = source;
            SinkConnectorInfo = sink;
        }

        public void SetPathGeneratorParameter(double? smoothMargin, double? smoothAutoSlope, double? orthogonalShapeMargin, double? orthogonalGlobalBoundsMargin)
        {
            bool hasChanged = false;
            if (smoothMargin != null && SmoothMargin != smoothMargin)
            {
                hasChanged = true;
                SmoothMargin = smoothMargin.Value;
            }
            if (smoothAutoSlope != null && SmoothAutoSlope != smoothAutoSlope)
            {
                hasChanged = true;
                SmoothAutoSlope = smoothAutoSlope.Value;
            }
            if (orthogonalShapeMargin != null && OrthogonalShapeMargin != orthogonalShapeMargin)
            {
                hasChanged = true;
                OrthogonalShapeMargin = orthogonalShapeMargin.Value;
            }
            if (orthogonalGlobalBoundsMargin != null && OrthogonalGlobalBoundsMargin != orthogonalGlobalBoundsMargin)
            {
                hasChanged = true;
                OrthogonalGlobalBoundsMargin = orthogonalGlobalBoundsMargin.Value;
            }
            if (hasChanged)
            {
                UpdatePathGeneratorResult();
            }
        }

        public void SetVisible(bool visible)
        {
            Visible = visible;
        }

        public double GetSourceMarkerWidth()
        {
            if (string.IsNullOrEmpty(ShapeViewModel.SourceMarker.Path))
            {
                return 0;
            }
            return ShapeViewModel.SourceMarker.Width;
        }

        public double GetSourceMarkerHeight()
        {
            if (string.IsNullOrEmpty(ShapeViewModel.SourceMarker.Path))
            {
                return 0;
            }
            return ShapeViewModel.SourceMarker.Height;
        }

        public double GetSinkMarkerWidth()
        {
            if (string.IsNullOrEmpty(ShapeViewModel.SinkMarker.Path))
            {
                return 0;
            }
            return ShapeViewModel.SinkMarker.Width;
        }

        public double GetSinkMarkerHeight()
        {
            if (string.IsNullOrEmpty(ShapeViewModel.SinkMarker.Path))
            {
                return 0;
            }
            return ShapeViewModel.SinkMarker.Height;
        }

        #region 双击添加
        private void AddVertex(object parameter)
        {
            MouseButtonEventArgs mosueArg = ((EventToCommandArgs)parameter).EventArgs as MouseButtonEventArgs;
            var position = mosueArg.GetPosition(((EventToCommandArgs)parameter).Sender as IInputElement);

            AddVertex(position, false);

            if (!((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control))
            {
                ShouldInsertAnchor = false;
            }
        }

        public void AddVertex(PointBase pointBase, bool absolute = true)
        {
            if (absolute)
            {
                pointBase = new PointBase(pointBase.X - Area.Left, pointBase.Y - Area.Top);
            }
            var vertice = new ConnectorVertexModel(this, pointBase);
            vertice.ColorViewModel.LineColor.Color = Colors.Blue;
            vertice.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
            Vertices.Add(vertice);
            UpdatePathGeneratorResult();
        }

        public ConnectorVertexModel AddEndsVertex(PointBase pointBase, ConnectorVertexType connectorVertexType)
        {
            var vertice = new ConnectorVertexModel(this, pointBase);
            vertice.ConnectorVertexType= connectorVertexType;
            vertice.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
            Vertices.Add(vertice);

            return vertice;
        }

        public void RemoveVertex(ConnectorVertexModel vertice)
        {
            Vertices.Remove(vertice);
            UpdatePathGeneratorResult();
        }

        protected override void ExecuteEditCommand(object param)
        {
            AddLabel();
        }

        public void AddLabel(string text = null, double? distance = null, PointBase? offset = null)
        {
            var label = new ConnectorLabelModel(this, text?.ToString(), distance, offset);
            label.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
            label.IsSelected = true;
            Labels.Add(label);

            var paths = Labels.Count > 0 ? PathGeneratorResult?.Paths.Select(p => new SvgPath(p)).ToArray() : Array.Empty<SvgPath>();
            label.UpdatePosition(paths);
        }

        public void RemoveLabel(ConnectorLabelModel label)
        {
            Labels.Remove(label);
        }

        public void ClearLabel()
        {
            Labels?.Clear();
        }
        #endregion
    }
}
